<template>
  <div id="cube-wrap">
    <div id="cube"></div>
  </div>
  <div id='container'>
    <svg id='display' viewBox='-220,-220,440,440'>
      <defs>
        <marker id='bezierCurveTerminalMarker' markerWidth='4' markerHeight='4' refX='2' refY='2'>
          <circle cx='2' cy='2' r='2' fill='skyblue'></circle>
        </marker>
      </defs>

      <g>
        <g>
          <!-- 网格 -->
          <line x1='-200' y1='-200' x2='230' y2='-200' stroke='lightgrey' stroke-width='2'></line>
          <line x1='-200' y1='-160' x2='200' y2='-160' stroke='#eeeeee'></line>
          <line x1='-200' y1='-120' x2='200' y2='-120' stroke='#eeeeee'></line>
          <line x1='-200' y1='-80' x2='200' y2='-80' stroke='#eeeeee'></line>
          <line x1='-200' y1='-40' x2='200' y2='-40' stroke='#eeeeee'></line>
          <line x1='-200' y1='0' x2='200' y2='0' stroke='#eeeeee'></line>
          <line x1='-200' y1='40' x2='200' y2='40' stroke='#eeeeee'></line>
          <line x1='-200' y1='80' x2='200' y2='80' stroke='#eeeeee'></line>
          <line x1='-200' y1='120' x2='200' y2='120' stroke='#eeeeee'></line>
          <line x1='-200' y1='160' x2='200' y2='160' stroke='#eeeeee'></line>
          <line x1='-230' y1='200' x2='200' y2='200' stroke='lightgrey' stroke-width='2'></line>
          <line x1='-200' y1='-200' x2='-200' y2='230' stroke='lightgrey' stroke-width='2'></line>
          <line x1='-160' y1='-200' x2='-160' y2='200' stroke='#eeeeee'></line>
          <line x1='-120' y1='-200' x2='-120' y2='200' stroke='#eeeeee'></line>
          <line x1='-80' y1='-200' x2='-80' y2='200' stroke='#eeeeee'></line>
          <line x1='-40' y1='-200' x2='-40' y2='200' stroke='#eeeeee'></line>
          <line x1='0' y1='-200' x2='0' y2='200' stroke='#eeeeee'></line>
          <line x1='40' y1='-200' x2='40' y2='200' stroke='#eeeeee'></line>
          <line x1='80' y1='-200' x2='80' y2='200' stroke='#eeeeee'></line>
          <line x1='120' y1='-200' x2='120' y2='200' stroke='#eeeeee'></line>
          <line x1='160' y1='-200' x2='160' y2='200' stroke='#eeeeee'></line>
          <line x1='200' y1='-230' x2='200' y2='200' stroke='lightgrey' stroke-width='2'></line>
          <text x='-218' y='220' fill='grey' style='font-size:20px;'>0</text>
          <text x='206' y='-206' fill='grey' style='font-size:20px;'>1</text>
        </g>
        <g>
          <!-- 曲线 -->
          <path id='controlLineBottom' d='M -200 200 L 200 200' fill='none' stroke='#fa65ac' stroke-width='3'
            data-start='-200 200'></path>
          <path id='controlLineTop' d='M 200 -200 L -200 -200' fill='none' stroke='#fa65ac' stroke-width='3'
            data-start='200 -200'></path>
          <circle id='controlPointBottom' data-type='bottom' cx='200' cy='200' r='8' fill='#fa65ac'></circle>
          <circle id='controlPointTop' data-type='top' cx='-200' cy='-200' r='8' fill='#fa65ac'></circle>
          <path id='bezierCurve' d='M -200 200 C 200 200 -200 -200 200 -200' fill='none' stroke='skyblue'
            stroke-width='4'></path>
          <circle cx='-200' cy='200' r='4' fill='skyblue'></circle>
          <circle cx='200' cy='-200' r='4' fill='skyblue'></circle>
        </g>
      </g>
    </svg>
    <div id='control'>
      <div id='controlPointCoordinateTop'>
        控制点 1：
        <input id='controlPointCoordinateTopX' class='controlPointCoordinate' type='text' autocomplete='off'
          title='输入范围：[0,1]' value='0.00' data-default='0' data-type='top' data-axis='x' data-lastvalue='' />
        <input id='controlPointCoordinateTopY' class='controlPointCoordinate' type='text' autocomplete='off'
          title='输入范围：[-∞,∞]' value='1.00' data-default='1' data-type='top' data-axis='y' data-lastvalue='' />
      </div>
      <div id='controlPointCoordinateBottom'>
        控制点 2：
        <input id='controlPointCoordinateBottomX' class='controlPointCoordinate' type='text' autocomplete='off'
          title='输入范围：[0,1]' value='1.00' data-default='1' data-type='bottom' data-axis='x' data-lastvalue='' />
        <input id='controlPointCoordinateBottomY' class='controlPointCoordinate' type='text' autocomplete='off'
          title='输入范围：[-∞,∞]' value='0.00' data-default='0' data-type='bottom' data-axis='y' data-lastvalue='' />
      </div>
      <input id='generateCssButton' type='button' value='生成 CSS' />
      <div id='message'>CSS 语句已复制到剪贴板</div>
    </div>
  </div>
</template>

<style>
  input,
  input:focus {
    border: none;
    background: none;
    outline: 0;
    font-family: 'Microsoft JhengHei', 'Microsoft YaHei', sans-serif;
  }

  #container {
    --ContainerSize: 400px;

    display: flex;
    justify-content: center;
    align-items: center;
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-200px, -50%);
    height: var(--ContainerSize);
    font-size: 0;
    /*去除display和control之间的间隙*/
    user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    -webkit-user-select: none;
  }

  #cube-wrap {
    position: relative;
    width: 70vw;
    margin: auto;
  }

  #cube-wrap::before {
    content: '';
    z-index: 10;
    display: inline-block;
    position: absolute;
    left: 0;
    top: 0;
    height: 100%;
    border-left: 2px solid grey;
  }

  #cube-wrap::after {
    content: '';
    z-index: 10;
    display: inline-block;
    position: absolute;
    right: 0;
    top: 0;
    height: 100%;
    border-right: 2px solid grey;
  }

  #cube {
    width: 100px;
    height: 100px;
    background: orange;
    animation: move 3s forwards infinite ease-in-out;
  }

  @keyframes move {
    from {
      transform: translateX(0);
      background-color: skyblue;
    }

    to {
      transform: translateX(calc(70vw - 100px));
      background-color: pink;
    }
  }

  #display {
    flex-basis: var(--ContainerSize);
    flex-shrink: 0;
    width: var(--ContainerSize);
    height: 1600px;
  }

  #controlPointBottom,
  #controlPointTop {
    cursor: pointer;
  }

  #controlPointBottom.focus,
  #controlPointBottom:hover,
  #controlPointTop.focus,
  #controlPointTop:hover {
    fill: red;
    r: 10;
  }

  #control {
    position: relative;
    width: 14rem;
    font-size: 1.2rem;
  }

  #controlPointCoordinateTop,
  #controlPointCoordinateBottom {
    width: 100%;
    height: 2.5rem;
  }

  .controlPointCoordinate {
    display: inline-block;
    width: 2.7rem;
    border-bottom: 1px solid lightgrey;
    margin: 0 0.3rem;
    text-align: center;
    font-size: 1.1rem;
    color: black;
  }

  .controlPointCoordinate:focus {
    border-bottom: 2px solid skyblue;
  }

  #generateCssButton {
    display: block;
    width: 6rem;
    height: 1.8rem;
    border: 1px solid currentColor;
    border-radius: 0.4rem;
    margin: 0.7rem auto;
    font-size: 1rem;
    line-height: 1.8rem;
    text-align: center;
    color: grey;
    cursor: pointer;
  }

  #generateCssButton:hover {
    color: skyblue;
  }

  #message {
    position: relative;
    left: 50%;
    width: 80%;
    padding-top: 0.5rem;
    transform: translateX(-50%);
    border-top: 1px solid lightgrey;
    font-size: 0.9rem;
    text-align: center;
    color: blue;
    opacity: 0;
  }

  #message.show {
    animation: generateCssButton_showAnimation 6s cubic-bezier(1.00, 0.00, 0.64, 0.22);
  }

  @keyframes generateCssButton_showAnimation {
    0% {
      opacity: 1;
    }

    100% {
      opacity: 0;
    }
  }
</style>

<script>
  /*成员*/

  let message = null;
  let bezierCurve = null;
  let controlLine =
  {
    bottom: null,
    top: null
  };
  let controlPoint =
  {
    bottom: null,
    top: null
  };
  let controlPointCoordinate =
  {
    bottom:
    {
      x: null,
      y: null
    },
    top:
    {
      x: null,
      y: null
    }
  };
  let temp =
  {
    bottom:
    {
      x: 200,
      y: 200
    },
    top:
    {
      x: -200,
      y: -200
    }
  };

  /**
   * @name 设置控制点 
   * @type Function
   * @param {String} type 类型
   * @param {Number} x 横坐标
   * @param {Number} y 纵坐标
   */
  let setControlPoint = function (type, x, y) {
    temp[type].x = x;
    temp[type].y = y;

    controlPoint[type].setAttribute('cx', x);
    controlPoint[type].setAttribute('cy', y);
    controlLine[type].setAttribute('d', `M ${controlLine[type].getAttribute('data-start')} L ${x} ${y}`);
    bezierCurve.setAttribute('d', `M -200 200 C ${temp.bottom.x} ${temp.bottom.y} ${temp.top.x} ${temp.top.y} 200 -200`);
  };
  /**
   * @name 激活输入
   * @type Function
   * @param {Object} input 发起激活的输入框
   */
  let activateInput = function (input) {
    let value = parseFloat(input.value);
    if (Number.isNaN(value))
      input.value = input.getAttribute('data-default');

    if ((input.getAttribute('data-axis')) === 'x') {
      let value = parseFloat(input.value);
      value = value > 1 ? 1 : value;
      value = value < 0 ? 0 : value;
      input.value = value;
    }

    let type = input.getAttribute('data-type');
    let x = parseFloat(controlPointCoordinate[type].x.value) * 400 - 200;
    let y = 200 - parseFloat(controlPointCoordinate[type].y.value) * 400;
    setControlPoint(type, x, y);
  };

  /**
   * @name 事件处理_控制点_鼠标按下
   * @type Function
   * @param {Object} ev 事件对象
   */
  let handler_controlPoint_mouseDown = function (ev) {
    this.classList.add('focus');
    this.CubicBezierToolData.lastX = ev.clientX;
    this.CubicBezierToolData.lastY = ev.clientY;

    let handlerMouseMove = (ev) => {
      let deltaX = ev.clientX - this.CubicBezierToolData.lastX;
      let deltaY = ev.clientY - this.CubicBezierToolData.lastY;
      let type = this.getAttribute('data-type');

      let x = temp[type].x + deltaX;
      x = x < -200 ? -200 : x;
      x = x > 200 ? 200 : x;
      let y = temp[type].y + deltaY;
      setControlPoint(type, x, y);

      let xCoordinate = (x + 200) / 400;
      let yCoordinate = (200 - y) / 400;
      controlPointCoordinate[type].x.value = xCoordinate.toFixed(2);
      controlPointCoordinate[type].y.value = yCoordinate.toFixed(2);

      this.CubicBezierToolData.lastX = ev.clientX;
      this.CubicBezierToolData.lastY = ev.clientY;
    };

    document.addEventListener('mousemove', handlerMouseMove);
    document.addEventListener('mouseup', () => {
      this.classList.remove('focus');
      document.removeEventListener('mousemove', handlerMouseMove);
    });
  };
  /**
   * @name 事件处理_控制点坐标_键盘按下
   * @type Function
   */
  let handler_controlPointCoordinate_keyPress = function (ev) {
    this.CubicBezierToolData.lastvalue = this.value;

    // let keyCode=ev.keyCode || ev.which;
    // if(keyCode!==46 && (keyCode<48 || keyCode>57))     //非数字或小数点
    //     ev.preventDefault();
  };
  /**
   * @name 事件处理_控制点坐标_键盘抬起
   * @type Function
   */
  let handler_controlPointCoordinate_keyUp = function (ev) {
    if ((ev.keyCode || ev.which) === 13)
      activateInput(this);
  };
  /**
   * @name 事件处理_控制点坐标_输入
   * @type Function
   */
  let handler_controlPointCoordinate_input = function () {
    if (!/^\d*\.?\d*$/.test(this.value))
      this.value = this.CubicBezierToolData.lastvalue;
  };
  /**
   * @name 事件处理_控制点坐标_得到焦点
   * @type Function
   */
  let handler_controlPointCoordinate_focus = function () {
    controlPoint[this.getAttribute('data-type')].classList.add('focus');
  };
  /**
   * @name 事件处理_控制点坐标_失去焦点
   * @type Function
   */
  let handler_controlPointCoordinate_blur = function () {
    controlPoint[this.getAttribute('data-type')].classList.remove('focus');
    activateInput(this);
  };
  /**
   * @name 事件处理_生成CSS按钮_点击
   * @type Function
   */
  let handler_generateCssButton_click = function () {
    let x1 = controlPointCoordinate.bottom.x.value;
    let y1 = controlPointCoordinate.bottom.y.value;
    let x2 = controlPointCoordinate.top.x.value;
    let y2 = controlPointCoordinate.top.y.value;
    let statement = `cubic-bezier(${x1},${y1},${x2},${y2})`;
    // Clipboard.copy(statement);

    // message.classList.remove('show');
    // setTimeout(() => { message.classList.add('show'); }, 0);

    document.querySelector('#cube').style['animation-timing-function'] = statement
  };

  /**
   * @name 剪贴板
   * @type Object
   */
  const Clipboard = (function () {
    /*成员*/

    let copyDummy;
    /**
     * @name 初始化
     * @type Function
     * @see Clipboard
     */
    let initiate = function () {
      let textarea = document.createElement('textarea');
      textarea.style = 'position:absolute; width:0; height:0; opacity:0;';
      copyDummy = textarea;
      document.body.appendChild(copyDummy);
    };

    /*接口*/

    /**
     * @name 复制
     * @type Function
     * @see Clipboard
     * @param {String} value 内容
     */
    let copy = function (value) {
      copyDummy.value = value;
      copyDummy.select();
      document.execCommand('Copy');
    };

    /*构造*/

    document.addEventListener('DOMContentLoaded', initiate);

    return { copy };
  })();

  /*接口*/

  /**
   * @name 初始化
   * @type Function
   */
  const initiate = function () {
    message = document.getElementById('message');
    bezierCurve = document.getElementById('bezierCurve');
    controlLine.bottom = document.getElementById('controlLineBottom');
    controlLine.top = document.getElementById('controlLineTop');
    controlPoint.bottom = document.getElementById('controlPointBottom');
    controlPoint.bottom.CubicBezierToolData = {};
    controlPoint.top = document.getElementById('controlPointTop');
    controlPoint.top.CubicBezierToolData = {};
    controlPointCoordinate.bottom.x = document.getElementById('controlPointCoordinateBottomX');
    controlPointCoordinate.bottom.y = document.getElementById('controlPointCoordinateBottomY');
    controlPointCoordinate.top.x = document.getElementById('controlPointCoordinateTopX');
    controlPointCoordinate.top.y = document.getElementById('controlPointCoordinateTopY');

    controlPoint.bottom.addEventListener('mousedown', handler_controlPoint_mouseDown);
    controlPoint.top.addEventListener('mousedown', handler_controlPoint_mouseDown);

    let controlPointCoordinates = Array.from(document.getElementsByClassName('controlPointCoordinate'));
    for (let el of controlPointCoordinates) {
      el.CubicBezierToolData = {};
      el.addEventListener('keypress', handler_controlPointCoordinate_keyPress);
      el.addEventListener('keyup', handler_controlPointCoordinate_keyUp);
      el.addEventListener('input', handler_controlPointCoordinate_input);
      el.addEventListener('focus', handler_controlPointCoordinate_focus);
      el.addEventListener('blur', handler_controlPointCoordinate_blur);
    }
    document.getElementById('generateCssButton').addEventListener('click', handler_generateCssButton_click);
  };

  /*构造*/

  initiate()
</script>